package com.webdrider.dao;

import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.common.dao.util.Criteria;
import com.common.model.util.UserType;
import com.common.security.exceptions.DatabaseException;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.webdrider.dao.action.user.UserDao;
import com.webdrider.model.action.user.User;

public class UserDaoTest {
	
	private final LocalServiceTestHelper helper = 
			new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
	
	@Before
	public void setUp() {
		helper.setUp();
	}
	
	@After
	public void tearDown() {
		helper.tearDown();
	}
	
	@Test
	public void testSaveUserSuccessfully() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(10L);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		user = dao.getById(10L);
		
		Assert.assertEquals(1, dao.getAll().size());
		Assert.assertNotNull(user);
		Assert.assertEquals("random username", user.getUsername());
		Assert.assertEquals("random password", user.getPassword());
		Assert.assertEquals(UserType.USER, user.getUserType());
	}
	
	@Test
	public void testDoubleSaveUserSuccesfully() throws DatabaseException {
		UserDao dao = new UserDao();
		User user1 = new User();
		User user2 = new User();
		
		user1.setUserType(UserType.USER);
		user2.setUserType(UserType.USER);
		
		Assert.assertEquals(0, dao.getAll().size());
		dao.save(user1);
		dao.save(user2);
		
		Assert.assertEquals(2, dao.getAll().size());
	}
	
	@Test
	public void testUpdateUserSuccesfully() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(5L);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		dao.save(user);
		
		Assert.assertEquals(1, dao.getAll().size());
		
		user.setPassword("new password");
		user.setUsername("new username");
		user.setUserType(UserType.ADMIN);
		dao.update(user);
		user = dao.getById(5L);
		
		Assert.assertNotNull(user);
		Assert.assertEquals(1, dao.getAll().size());
		Assert.assertEquals("new username", user.getUsername());
		Assert.assertEquals("new password", user.getPassword());
		Assert.assertEquals(UserType.ADMIN, user.getUserType());
	}
	
	@Test
	public void testRemoveUserSuccesfully() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(6L);
		user.setUserType(UserType.USER);
		dao.save(user);
		
		Assert.assertEquals(1, dao.getAll().size());
		
		dao.delete(user);
		Assert.assertEquals(0, dao.getAll().size());
	}
	
	@Test
	public void testUserNotFound() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = dao.getById(5L);
		
		Assert.assertNull(user);
	}

	@Test
	public void testGetByCriteria() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(10L);
		user.setOnline(false);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		Assert.assertEquals(1, dao.getAll().size());
		
		List<User> users = dao.getByCriteria(new Criteria("username", "random username", true));
		Assert.assertEquals(1, users.size());
		
		User resultUser = users.get(0);
		Assert.assertNotNull(resultUser);
		Assert.assertEquals("random username", resultUser.getUsername());
		Assert.assertEquals("random password", resultUser.getPassword());
		Assert.assertEquals(UserType.USER, resultUser.getUserType());
	}
	
	@Test
	public void testGetByOneCriteria() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(10L);
		user.setOnline(false);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		Assert.assertEquals(1, dao.getAll().size());
		
		List<Criteria> criterias = new ArrayList<Criteria>();
		criterias.add(new Criteria("id", 10L, false));
		
		List<User> users = dao.getByCriteria(criterias);
		Assert.assertEquals(1, users.size());
		
		User resultUser = users.get(0);
		Assert.assertNotNull(resultUser);
		Assert.assertEquals("random username", resultUser.getUsername());
		Assert.assertEquals("random password", resultUser.getPassword());
		Assert.assertEquals(UserType.USER, resultUser.getUserType());
	}
	
	@Test
	public void testGetByTwoCriteria() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(10L);
		user.setOnline(false);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		Assert.assertEquals(1, dao.getAll().size());
		
		List<Criteria> criterias = new ArrayList<Criteria>();
		criterias.add(new Criteria("id", 10L, false));
		criterias.add(new Criteria("online", "false", false));
		
		List<User> users = dao.getByCriteria(criterias);
		Assert.assertEquals(1, users.size());
		
		User resultUser = users.get(0);
		Assert.assertNotNull(resultUser);
		Assert.assertEquals("random username", resultUser.getUsername());
		Assert.assertEquals("random password", resultUser.getPassword());
		Assert.assertEquals(UserType.USER, resultUser.getUserType());
	}
	
	@Test
	public void testGetByTwoCriteriaNotFound() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setId(10L);
		user.setOnline(true);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		Assert.assertEquals(1, dao.getAll().size());
		
		List<Criteria> criterias = new ArrayList<Criteria>();
		criterias.add(new Criteria("id", "10", false));
		criterias.add(new Criteria("online", "false", false));
		
		List<User> users = dao.getByCriteria(criterias);
		Assert.assertEquals(0, users.size());
	}
	
	@Test
	public void testGetByEnumUserTypeCriteria() throws DatabaseException {
		UserDao dao = new UserDao();
		User user = new User();
		
		Assert.assertEquals(0, dao.getAll().size());
		
		user.setOnline(true);
		user.setPassword("random password");
		user.setUsername("random username");
		user.setUserType(UserType.USER);
		
		dao.save(user);
		Assert.assertEquals(1, dao.getAll().size());
		
		List<Criteria> criterias = new ArrayList<Criteria>();
		criterias.add(new Criteria(User.USER_TYPE, UserType.USER, true));
		
		List<User> users = dao.getByCriteria(criterias);
		Assert.assertEquals(1, users.size());
		
		User resultUser = users.get(0);
		Assert.assertNotNull(resultUser);
		Assert.assertEquals("random username", resultUser.getUsername());
		Assert.assertEquals("random password", resultUser.getPassword());
		Assert.assertEquals(UserType.USER, resultUser.getUserType());
	}
}
